# Module is functional AS IS. As for now only run within Eclipse is supported.
# API seems stable, implementation needs refactor.

from __future__ import absolute_import

import ConfigParser
import unittest
import json
import os
import logging
from sqlalchemy import create_engine
from tinyesb.process import mediation

import scopt.mpu as mpu
from scopt.util.json_s import clear
import scopt.util.i18n as i18n
from scopt.mpu.security.db_registry.handlers import authenticate_login_password
from scopt.mpu.security.db_registry.handlers import flyby_token
from scopt.mpu.security import db_registry
from scopt.mpu import context
from scopt.mpu import business
from scopt.util.message import in_data_packet
from scopt.mpu.context.tenant.handlers import create
from scopt.mpu.business.devel.handlers import echo

_file_ext = os.path.splitext(__file__)[1]
_path = 'lib{0}{1}{2}'.format(os.sep, __name__.replace('.', os.sep), _file_ext)
_APP_ROOT = __file__.replace(_path, '')

_CONFIG = ConfigParser.RawConfigParser()
_CONFIG.read(os.path.join(_APP_ROOT, 'scopt.cfg'))
_CONFIG.set('APP', 'DATA_DIR', os.path.join(_APP_ROOT, "data_test"))

DEFAULT_LOGIN = 'scopt'
DEFAULT_PASSWORD = 'admin'
DEFAULT_MESSAGE_FORMAT = 'scopt'
DEFAULT_TENANT_ID = 'TENANTX'
DEFAULT_LANGUAGE = 'en_EN'
_LOGIC = None
_DBS = {'security': {'metadata': db_registry.model.get(),
                     'engine': None},
        'context': {'metadata': context.model.get(),
                    'engine': None},
        'business': {'metadata': business.MODEL,
                     'engine': None}}


def _adapt_url(raw_url, data_dir, tenant_id):
    return raw_url\
            .replace('{DATA_DIR}', data_dir)\
            .replace('{TENANT_ID}', tenant_id)

_data_dir = _CONFIG.get('APP', 'DATA_DIR')
_security_url = _adapt_url(_CONFIG.get('SECURITY', 'url'),
                           _data_dir,
                           DEFAULT_TENANT_ID)
_context_url = _adapt_url(_CONFIG.get('CONTEXT', 'url'),
                          _data_dir,
                          DEFAULT_TENANT_ID)
_business_url = _adapt_url(_CONFIG.get('lds/BDS', 'url'),
                           _data_dir,
                           DEFAULT_TENANT_ID)

_DBS['security']['engine'] = create_engine(_security_url, echo=False)
_DBS['context']['engine'] = create_engine(_context_url, echo=False)
_DBS['business']['engine'] = create_engine(_business_url, echo=False)

i18n.install(mpu.I18N, 'sk')
logging.disable("WARNING")


class ScoptTest(unittest.TestCase):
    def setUp(self):
        self.__create_dbs()

        global _LOGIC
        global _CONFIG
        _LOGIC = mpu.firmware(_CONFIG)
        self.__tenant_create()

    def tearDown(self):
        self.__drop_dbs()

    def __create_dbs(self):
        for db in _DBS.values():
            db['metadata'].create_all(db['engine'])

    def __drop_dbs(self):
        for db in _DBS.values():
            db['metadata'].drop_all(db['engine'])

    def request(self, handler):
        request = handler.REQUEST()
        reqh = request['reqh']
        reqh['tenant_id'] = DEFAULT_TENANT_ID
        reqh['security'] = {}
        reqh['language'] = DEFAULT_LANGUAGE
        reqh['format'] = DEFAULT_MESSAGE_FORMAT
        reqh['message_id'] = '12345'
        reqh['version'] = '0.1'
        return request

    def dummy_request(self):
        request = self.request(echo.echo)
        request['reqd']['text'] = 'Hello World!'
        request['reqh']['tenant_id'] = DEFAULT_TENANT_ID
        return request

    def assertStatus(self, response, *status):
        res_status = response['resh']['status']
        ass_status = status[0]
        self.assertEqual(res_status, ass_status)
        if ass_status == 'INT':
            res_reason = response['resd']['reason']
            if res_reason == 'EXCEPTION':
                exc_code = response['resd']['code']
                ass_code = status[1]
                self.assertEqual(exc_code, ass_code)

    def send_request(self, request, token=None, pass_interrupts=False):
        if token is None:
            handler = flyby_token.handle
            token = handler.TOKEN()
            token['value'] = self.__authenticate()

        request['reqh']['security'] = token
        response = self.__begin_mediation(request)

        if response['resh']['status'] == 'INT' and not pass_interrupts:
            raise StandardError

        return response

    def __begin_mediation(self, request):
        json_dump = json.dumps(request, default=clear)
        data_packet = in_data_packet(json_dump)
        data_packet = mediation.mediate(data_packet,
                                        _LOGIC,
                                        'HTTP_IN',
                                        mpu.exception_handler)
        raw_response = data_packet['message']['raw_response']
        return json.loads(raw_response)

    def __tenant_create(self):
        request = self.request(create.handle)
        request['reqd']['tenant_name'] = DEFAULT_TENANT_ID
        request['reqd']['params'] = {'Color': 'ABS',
                                     'demo': True}
        self.send_request(request)

    def __authenticate(self):
        request = self.request(echo.echo)
        handler = authenticate_login_password.handle
        token = handler.TOKEN()
        token['login'] = DEFAULT_LOGIN
        token['password'] = DEFAULT_PASSWORD

        response = self.send_request(request, token)
        return response['resd']['token']
